/*****************************************************************************
 *	      ______
 *	    /   _   \   _   __    ______
 *	   /  /_ /  / /  //__ / /   _   \
 *	  /   ____ / /   /     /  /  /  /
 *	 /  /       /  /      /  /_ /  /
 *	/_ /       /_ /       \ _____ /
 *	           ______
 *	         /  ____ /  ______     _   __     _    ______
 *	        /  /___   /   _   \  /  //_  \  /_ / /   _   \
 *	       _\___   \ /  /  /  / /   / /  / /  / /  /  /_ /
 *	     /  /_ /  / /  /_ /  / /  /  /  / /  / /  /____
 *	     \______ /  \ _____ / /_ /  /_ / /_ /  \ ______/
 *
 *
 *	ProSonic Engine
 *	Created by Damian Grove
 *
 *	Compiled with DJGPP - GCC 2.952 (DOS) / Dev-C++ 4.9.9.2 (Windows)
 *	Libraries used:
 *		- Allegro - 3.9.34		http://www.talula.demon.co.uk/allegro/
 *		- DUMB - 0.9.3			http://dumb.sourceforge.net/
 *		- AllegroOgg - 1.0.3	http://nekros.freeshell.org/delirium/
 *
 ******************************************************************************
 *
 *	NAME:	ProSonic - Object code and management
 *
 *	FILE:	objects.c
 *
 *	DESCRIPTION:
 *		This file contains code for game objects and their functionality. Also
 *	included is the node manager which gets rid of wasted memory space and
 *	organized the objects that are being used. The object buffer will hold up
 *	to 128 objects, and the total number of objects allowed in a single level
 *	is 1023.
 *
 *****************************************************************************/



#include	<stdio.h>							// Standard input/output
#include	<allegro.h>							// Allegro game library

#include	"error.h"
//#include	"draw.h"
//#include	"text.h"
#include	"m68k.h"
#include	"obj01.h"
#include	"objects.h"
#include	"sprites.h"
#include	"script.h"







void AllocateObjects(ZONE *z){
	short i;
	short n = z->Act[act].Stage[stage].ObjectLayout;
	int size = z->OBJ_SizeTable[n];
	int address = z->OBJ_AddressTable[n];

	if((int)(size_t)Objects != ENOMEM){
		free(Objects);
		Objects = 0;
	}

	for(i=0; i < MAX_LEVEL_OBJECTS; i++)
		ObjectStates[i] = 0;

	Objects = (OBJECT_PLOT*)malloc(size + (MAX_BUFFER_OBJECTS << 3));
	for(i=0; i < (size >> 3); i++){
		Objects[i].x_pos = (z->OBJ[address + (i << 3)] << 8) + z->OBJ[address + (i << 3) + 1];
		Objects[i].y_pos = (z->OBJ[address + (i << 3) + 2] << 8) + z->OBJ[address + (i << 3) + 3];
		Objects[i].type = z->OBJ[address + (i << 3) + 4];
		Objects[i].subtype = z->OBJ[address + (i << 3) + 5];
		Objects[i].h_tag = z->OBJ[address + (i << 3) + 6];
		Objects[i].l_tag = z->OBJ[address + (i << 3) + 7];
	}
	ObjectCount = (size >> 3);
	for(i = 0; i < MAX_BUFFER_OBJECTS; i++)
	{
		// Clear debug object memory
		ObjectNodes[i] = 0xFFFF;
		Objects[ObjectCount + i].x_pos = 0xFFFF;
		Objects[ObjectCount + i].y_pos = 0x0;
		Objects[ObjectCount + i].type = 0x0;
		Objects[ObjectCount + i].subtype = 0x0;
		Objects[ObjectCount + i].h_tag = 0x0;
		Objects[ObjectCount + i].l_tag = 0x0;

		// Clear object on-screen buffer memory
		objObject[i].static_node = 0;
		objObject[i].routine = 0;
		objObject[i].status = 0;
		objObject[i].render_flags = 0;
		objObject[i].width_pixels = 0;
		objObject[i].priority = 0;
		objObject[i].objoff_32 = 0;
		objObject[i].objoff_34 = 0;
		objObject[i].anim_frame_duration = 0;
		objObject[i].anim_frame = 0;
		objObject[i].anim = 0;
		objObject[i].x_pos_pre = 0;
		objObject[i].y_pos_pre = 0;
		objObject[i].x_vel = 0;
		objObject[i].y_vel = 0;
		objObject[i].x_radius = 0;
		objObject[i].x_radius = 0;
		for(n=0; n < 16; n++)
			objObject[i].user[n] = 0;
		for(n=0; n < 0x1300; n++)
			objObject[i].ram[n] = 0;
	}
}







// This manages object nodes. Object nodes keep track of what objects are in
// memory. This function constantly swaps in objects that enter the play area,
// and swaps out objects that are outside the play area. This is important
// since ProSonic supports 128 objects in the play area at one time.
FUNCINLINE void ManageObjectNodes(ZONE *z)
{
	int a;
	int b;
	//int c;
	short	LimitL = p->Camera_X_pos - OBJECT_BUFFER_SCOPE;
	short	LimitR = p->Camera_X_pos + OBJECT_BUFFER_SCOPE + screen_resolution_x;
	unsigned short	ObjectNumber;
	unsigned short	NodeNumber = 0;

	if(frame == 1){
		for(a=0; a < MAX_BUFFER_OBJECTS; a++){
			if(ObjectScopePoll[a] >= num_of_frames){
				objObject[a].user[0] = 0;
					objObject[a].user[1] = 0;
					objObject[a].user[2] = 0;
					objObject[a].user[3] = 0;
					objObject[a].user[4] = 0;
					objObject[a].user[5] = 0;
					objObject[a].user[6] = 0;
					objObject[a].user[7] = 0;
					objObject[a].user[8] = 0;
					objObject[a].user[9] = 0;
					objObject[a].user[10] = 0;
					objObject[a].user[11] = 0;
					objObject[a].user[12] = 0;
					objObject[a].user[13] = 0;
					objObject[a].user[14] = 0;
					objObject[a].user[15] = 0;

					objObject[a].routine = 0;
					objObject[a].x_pos = 0;
					objObject[a].y_pos = 0;
					objObject[a].render_flags = 0;
					objObject[a].priority = 0;
					objObject[a].subtype = 0;
					objObject[a].objoff_32 = 0;
					objObject[a].objoff_34 = 0;
					objObject[a].type = 0;
					objObject[a].subtype = 0;
					objObject[a].h_tag = 0;
					objObject[a].l_tag = 0;
					objObject[a].x_pos_pre = 0;
					objObject[a].y_pos_pre = 0;
					objObject[a].x_vel = 0;
					objObject[a].y_vel = 0;
					objObject[a].x_radius = 0;
					objObject[a].x_radius = 0;

					objObject[a].static_node = 0;

					objObject[a].status = 0;

					for(i=0; i < 0x1300; i++)
						objObject[a].ram[i] = 0;

					ObjectNodes[a] = 0xFFFF;
			}
			ObjectScopePoll[a] = 0;
		}
	}

	if(LimitL < 0)
		LimitL = 0;
	if(LimitR < 0)
		LimitR = 0;

	// Find the first object within the object scope
	for(ObjectNumber = 0;
		(Objects[ObjectNumber].x_pos < LimitL && ObjectNumber < ObjectCount)
		|| Objects[ObjectNumber].type == 0;
		ObjectNumber++);




	// Code for permanent objects
	for(; Objects[ObjectNumber].x_pos < LimitR && ObjectNumber < ObjectCount; ObjectNumber++)
	{
		if(Objects[ObjectNumber].type > 0)
		{
			for(a = 0; a < MAX_BUFFER_OBJECTS; a++)
			{
				if(ObjectNodes[a] == ObjectNumber)
				{
					b = 1;					// Object is listed in the nodes table
					a = MAX_BUFFER_OBJECTS;	// Stop checking for exisitng node
				}
				else
					b = 0;					// Object is NOT listed at the current node
			}
			if(b == 0)	// If object is NOT listed in the nodes table
			{
				for(a = 0; a < MAX_BUFFER_OBJECTS; a++)
				{
					if(ObjectNodes[a] >= MAX_LEVEL_OBJECTS)
					{
						ObjectNodes[a] = ObjectNumber;	// Put the object at the next available node
						BufferObjectCount = a + 1;

						objObject[a].x_pos = Objects[ObjectNumber].x_pos;
						objObject[a].y_pos = Objects[ObjectNumber].y_pos;
						objObject[a].type = Objects[ObjectNumber].type;
						objObject[a].subtype = Objects[ObjectNumber].subtype;
						objObject[a].h_tag = Objects[ObjectNumber].h_tag;
						objObject[a].l_tag = Objects[ObjectNumber].l_tag;

						a = MAX_BUFFER_OBJECTS;
						b = 1;	// Set to 1 to indicate no errors found
					}
				}
				if(b == 0)
					quit(ERROR_OBJECT_BUFFER);
			}
		}
	}



	// Code for temporary objects
	ObjectNumber = ObjectCount;
	for(; ObjectNumber < ObjectCount + MAX_BUFFER_OBJECTS; ObjectNumber++)
	{
		if(Objects[ObjectNumber].x_pos >= LimitL && Objects[ObjectNumber].x_pos < LimitR)
		{
			for(a = MAX_BUFFER_OBJECTS - 1; a >= 0; a--)
			{
				if(ObjectNodes[a] == ObjectNumber)
				{
					b = 1;					// Object is listed in the nodes table
					a = -1;					// Stop checking for exisitng node
				}
				else
					b = 0;					// Object is NOT listed at the current node
			}
			if(b == 0)	// If object is NOT listed in the nodes table
			{
				for(a = MAX_BUFFER_OBJECTS - 1; a >= 0; a--)	// added "- 1" --- 01/01/2006
				{
					if(ObjectNodes[a] >= MAX_LEVEL_OBJECTS)
					{
						ObjectNodes[a] = ObjectNumber;	// Put the object at the next available node
						a = -1;

						objObject[a].x_pos = Objects[ObjectNumber].x_pos;
						objObject[a].y_pos = Objects[ObjectNumber].y_pos;
						objObject[a].type = Objects[ObjectNumber].type;
						objObject[a].subtype = Objects[ObjectNumber].subtype;
						objObject[a].h_tag = Objects[ObjectNumber].h_tag;
						objObject[a].l_tag = Objects[ObjectNumber].l_tag;
					}
				}
			}
		}
		else
		{
			Objects[ObjectNumber].x_pos = 0xFFFF;
			Objects[ObjectNumber].y_pos = 0x0;
			Objects[ObjectNumber].type = 0x0;
			Objects[ObjectNumber].subtype = 0x0;
			Objects[ObjectNumber].h_tag = 0x0;
			Objects[ObjectNumber].l_tag = 0x0;
		}
	}







	for(NodeNumber = 0; NodeNumber < MAX_BUFFER_OBJECTS; NodeNumber++)
	{
		if(ObjectNodes[NodeNumber] < ObjectCount + MAX_BUFFER_OBJECTS)
        {
    		// We actually execute objects here
	    	if(ObjectNodes[NodeNumber] < MAX_LEVEL_OBJECTS){
				if((objObject[NodeNumber].x_pos >= LimitL && objObject[NodeNumber].x_pos < LimitR)
				 || objObject[NodeNumber].static_node){
		    		switch(Objects[ObjectNodes[NodeNumber]].type){
			    		case 0:		// NULL
			    			break;

			    		case 0x03:	// Side swapper
				    		fncSideSwapper(z, NodeNumber);
				    		break;

				    	case 0x25:	// Ring
					    	fncRing(z, NodeNumber);
					    	break;

					    default:	// *** 68000 emulation ***
					    	fncM68K(z, NodeNumber);
					}
				}
			}

			PollObject(NodeNumber);
		}
	}
}








FUNCINLINE void PollObject(unsigned short NodeNumber){
	short	LimitL = p->Camera_X_pos - OBJECT_BUFFER_SCOPE;
	short	LimitR = p->Camera_X_pos + OBJECT_BUFFER_SCOPE + screen_resolution_x;

	if(LimitL < 0)
		LimitL = 0;
	if(LimitR < 0)
		LimitR = 0;

	if(objObject[NodeNumber].x_pos < LimitL && !objObject[NodeNumber].static_node)
		PollObjectFrame(NodeNumber);
	else if(objObject[NodeNumber].x_pos >= LimitR && !objObject[NodeNumber].static_node)
		PollObjectFrame(NodeNumber);
}



void PollObjectFrame(unsigned short NodeNumber){
	if(ObjectNodes[NodeNumber] >= ObjectCount && ObjectNodes[NodeNumber] != 0xFFFF)	// If it's a temporary object, delete it from memory
	{
		Objects[ObjectNodes[NodeNumber]].x_pos = 0xFFFF;
		Objects[ObjectNodes[NodeNumber]].y_pos = 0x0;
		Objects[ObjectNodes[NodeNumber]].type = 0x0;
		Objects[ObjectNodes[NodeNumber]].subtype = 0x0;
		Objects[ObjectNodes[NodeNumber]].h_tag = 0x0;
		Objects[ObjectNodes[NodeNumber]].l_tag = 0x0;
		ObjectNodes[NodeNumber] = 0xFFFF;
	}
	if(ObjectNodes[NodeNumber] < MAX_LEVEL_OBJECTS){
		ObjectScopePoll[NodeNumber]++;
	}
}



void CreateObject(char type, char subtype, char h_tag, char l_tag, short x_pos, short y_pos)
{
	int a;
	short n = z.Act[act].Stage[stage].ObjectLayout;
	int size = z.OBJ_SizeTable[n];
	unsigned short ObjectCount = (size >> 3);

	for(a = MAX_BUFFER_OBJECTS - 1; a >= 0; a--)
	{
		if(ObjectNodes[a] >= MAX_LEVEL_OBJECTS)
		{
			ObjectNodes[a] = ObjectCount + a;
			Objects[ObjectCount + a].x_pos = x_pos;
			Objects[ObjectCount + a].y_pos = y_pos;
			Objects[ObjectCount + a].type = type;
			Objects[ObjectCount + a].subtype = subtype;
			Objects[ObjectCount + a].h_tag = h_tag;
			Objects[ObjectCount + a].l_tag = l_tag;

			objObject[a].x_pos = Objects[ObjectCount + a].x_pos;
			objObject[a].y_pos = Objects[ObjectCount + a].y_pos;
			objObject[a].type = Objects[ObjectCount + a].type;
			objObject[a].subtype = Objects[ObjectCount + a].subtype;
			objObject[a].h_tag = Objects[ObjectCount + a].h_tag;
			objObject[a].l_tag = Objects[ObjectCount + a].l_tag;

			a = 0;
		}
	}
}



// This will permanently write an object out of memory so it will never be
// loaded as a node again.
void DestroyObject(unsigned short NodeNumber)
{
	Objects[ObjectNodes[NodeNumber]].type = 0;	// Set object class to 0
	Objects[ObjectNodes[NodeNumber]].subtype = 0;	// Set object member to 0
	Objects[ObjectNodes[NodeNumber]].h_tag = 0;
	Objects[ObjectNodes[NodeNumber]].l_tag = 0;
	ObjectNodes[NodeNumber] = 0xFFFF;						// Free the node

	// Clear object on-screen buffer memory
	objObject[NodeNumber].x_pos = 0xFFFF;
	objObject[NodeNumber].y_pos = 0;
	objObject[NodeNumber].type = 0;
	objObject[NodeNumber].subtype = 0;
	objObject[NodeNumber].h_tag = 0;
	objObject[NodeNumber].l_tag = 0;
	objObject[NodeNumber].static_node = 0;
	objObject[NodeNumber].routine = 0;
	objObject[NodeNumber].status = 0;
	objObject[NodeNumber].render_flags = 0;
	objObject[NodeNumber].width_pixels = 0;
	objObject[NodeNumber].priority = 0;
	objObject[NodeNumber].objoff_32 = 0;
	objObject[NodeNumber].objoff_34 = 0;
	objObject[NodeNumber].anim_frame_duration = 0;
	objObject[NodeNumber].anim_frame = 0;
	objObject[NodeNumber].anim = 0;
	objObject[NodeNumber].x_pos_pre = 0;
	objObject[NodeNumber].y_pos_pre = 0;
	objObject[NodeNumber].x_vel = 0;
	objObject[NodeNumber].y_vel = 0;
	objObject[NodeNumber].x_radius = 0;
	objObject[NodeNumber].x_radius = 0;
	for(n=0; n < 16; n++)
		objObject[NodeNumber].user[n] = 0;
	for(n=0; n < 0x1300; n++)
		objObject[NodeNumber].ram[n] = 0;
}



// * 0B *
// Side swappers! Woohoo
FUNCINLINE void fncSideSwapper(ZONE *z, unsigned short NodeNumber){
	OBJECT			*o = &objObject[NodeNumber];
	short range[4] = { 0x20, 0x40, 0x80, 0x100 };

	if(o->user[0] == 0)
		o->user[0] = o->y_pos & 0xF800;

	//o->y_pos &= 0x7FF;		// temporary fix
	o->subtype = o->subtype;	// temporary fix
	o->anim = 0;
	//o->anim_counter = ObjectStates[ObjectNodes[NodeNumber]] << 1;
	//o->anim_speed = 1;

	// subtype: 76543210
	// 10 --- size
	// 2 ---- direction
	// 3 ---- layer coming in from left
	// 4 ---- layer coming in from right
	// 5 ---- plane coming in from left
	// 6 ---- plane coming in from right
	// 7 ---- if on, only works when on ground

	//DrawCounter16(LayerH[frame-1], o->subtype + (o->type << 8), o->x_pos - p->Camera_X_pos - 16 + 16, o->y_pos - (signed short)(p->Camera_Y_pos) - 16);
	//DrawCounter16(LayerSH[frame-1], ObjectStates[ObjectNodes[NodeNumber]] + (o->type << 8), o->x_pos - p->Camera_X_pos - 16 + 16, o->y_pos - (signed short)(p->Camera_Y_pos) - 16 + 16);
	//DrawCounter16(LayerH[frame-1], o->user[0], o->x_pos - p->Camera_X_pos - 16 + 16, o->y_pos - (signed short)(p->Camera_Y_pos) + 8);

	//int				x_pos = Objects[ObjectNodes[NodeNumber]].x_pos;
	//int				y_pos = Objects[ObjectNodes[NodeNumber]].y_pos;
	//int				ObjM = Objects[ObjectNodes[NodeNumber]].Member;

	switch(o->routine){
		case 0:
			goto Obj03_Init;
			break;
		case 2:
			goto Obj03_MainX;
			break;
		case 4:
			goto Obj03_MainY;
	}

Obj03_Init:
	o->render_flags |= 4;
	o->width_pixels = 0x10;
	o->priority = 5;

	if((o->subtype & 4) == 0)
		goto Obj03_Init_CheckX;

//Obj03_Init_CheckY:
	o->routine = 4;
	if(o->y_pos < p->y_pos)
		//ObjectStates[ObjectNodes[NodeNumber]] = 1;
		ObjectStates[ObjectNodes[NodeNumber]] |= (1 << (frame-1));

	goto Obj03_MainY;

Obj03_Init_CheckX:
	o->routine = 2;
	if(o->x_pos < p->x_pos)
		//ObjectStates[ObjectNodes[NodeNumber]] = 1;
		ObjectStates[ObjectNodes[NodeNumber]] |= (1 << (frame-1));

Obj03_MainX:
	if(Debug_placement_mode)
		return;

	//if(ObjectStates[ObjectNodes[NodeNumber]] == 0){
	if((ObjectStates[ObjectNodes[NodeNumber]] & (1 << (frame-1))) == 0){//////////////////////////////
		if(o->x_pos > p->x_pos)
			return;
	}
	else if(o->x_pos <= p->x_pos)
		return;

	//ObjectStates[ObjectNodes[NodeNumber]] ^= 1;
	ObjectStates[ObjectNodes[NodeNumber]] ^= (1 << (frame-1));
	if(p->y_pos < (o->y_pos - range[o->subtype & 3]))
		return;
	if(p->y_pos >= (o->y_pos + range[o->subtype & 3]))
		return;
	if(o->subtype < 0 && p->status & 2)
		return;

	if((o->render_flags & 1) == 0){
		//DrawText((screen_resolution_x >> 1) - 32, screen_resolution_y >> 1, 0x30, "ACTIVE!");
		p->layer = 0x10;
		p->layer_plus = 0x11;
		//if(ObjectStates[ObjectNodes[NodeNumber]] == 1){
		if(ObjectStates[ObjectNodes[NodeNumber]] & (1 << (frame-1))){
			if(o->subtype & 8){
				p->layer = 0x12;
				p->layer_plus = 0x13;
			}
		}
		else if(o->subtype & 0x10){
			p->layer = 0x12;
			p->layer_plus = 0x13;
		}
		/*WriteLog("MAIN_X");
		VarLog(VAR_LAYER);
		d0 = NodeNumber;
		d1 = ObjectNodes[NodeNumber];
		VarLog(REG_D0);
		VarLog(REG_D1);
		WriteLog("OBJECT==========");
		d2 = o->x_pos;
		d3 = o->y_pos;
		d4 = o->subtype;
		d7 = ObjectStates[ObjectNodes[NodeNumber]];
		VarLog(REG_D2);
		VarLog(REG_D3);
		VarLog(REG_D4);
		VarLog(REG_D7);
		WriteLog("PLAYER==========");
		d5 = p->x_pos;
		d6 = p->y_pos;
		VarLog(REG_D5);
		VarLog(REG_D6);*/
	}

	p->art_tile &= 0x7FFF;
	if(o->subtype & 0x20)
		p->art_tile |= 0x8000;
	return;

Obj03_MainY:
	if(Debug_placement_mode)
		return;

	//if(ObjectStates[ObjectNodes[NodeNumber]] != 0)
	if(ObjectStates[ObjectNodes[NodeNumber]] & (1 << (frame-1)))
		goto Obj03_MainY_Alt;

	if(o->y_pos > p->y_pos)
		return;

	//ObjectStates[ObjectNodes[NodeNumber]] = 1;
	ObjectStates[ObjectNodes[NodeNumber]] |= (1 << (frame-1));
	if(p->x_pos < (o->x_pos - range[o->subtype & 3]))
		return;
	if(p->x_pos >= (o->x_pos + range[o->subtype & 3]))
		return;
	if(o->subtype < 0 && p->status & 2)
		return;

	if((o->render_flags & 1) == 0){
		//DrawText((screen_resolution_x >> 1) - 32, screen_resolution_y >> 1, 0x30, "ACTIVE!");
		p->layer = 0x10;
		p->layer_plus = 0x11;
		if(o->subtype & 8){
			p->layer = 0x12;
			p->layer_plus = 0x13;
		}
		/*WriteLog("MAIN_Y");
		VarLog(VAR_LAYER);
		d0 = NodeNumber;
		d1 = ObjectNodes[NodeNumber];
		VarLog(REG_D0);
		VarLog(REG_D1);
		WriteLog("OBJECT==========");
		d2 = o->x_pos;
		d3 = o->y_pos;
		d4 = o->subtype;
		d7 = ObjectStates[ObjectNodes[NodeNumber]];
		VarLog(REG_D2);
		VarLog(REG_D3);
		VarLog(REG_D4);
		VarLog(REG_D7);
		WriteLog("PLAYER==========");
		d5 = p->x_pos;
		d6 = p->y_pos;
		VarLog(REG_D5);
		VarLog(REG_D6);*/
	}

	p->art_tile &= 0x7FFF;
	if(o->subtype & 0x20)
		p->art_tile |= 0x8000;
	return;

Obj03_MainY_Alt:
	if(o->y_pos <= p->y_pos)
		return;

	//ObjectStates[ObjectNodes[NodeNumber]] = 0;
	if(ObjectStates[ObjectNodes[NodeNumber]] & (1 << (frame-1)))
		ObjectStates[ObjectNodes[NodeNumber]] ^= (1 << (frame-1));
	if(p->x_pos < (o->x_pos - range[o->subtype & 3]))
		return;
	if(p->x_pos >= (o->x_pos + range[o->subtype & 3]))
		return;
	if(o->subtype < 0 && p->status & 2)
		return;

	if((o->render_flags & 1) == 0){
		//DrawText((screen_resolution_x >> 1) - 32, screen_resolution_y >> 1, 0x30, "ACTIVE!");
		p->layer = 0x10;
		p->layer_plus = 0x11;
		if(o->subtype & 0x10){
			p->layer = 0x12;
			p->layer_plus = 0x13;
		}
		/*WriteLog("MAIN_ALT");
		VarLog(VAR_LAYER);
		d0 = NodeNumber;
		d1 = ObjectNodes[NodeNumber];
		VarLog(REG_D0);
		VarLog(REG_D1);
		WriteLog("OBJECT==========");
		d2 = o->x_pos;
		d3 = o->y_pos;
		d4 = o->subtype;
		d7 = ObjectStates[ObjectNodes[NodeNumber]];
		VarLog(REG_D2);
		VarLog(REG_D3);
		VarLog(REG_D4);
		VarLog(REG_D7);
		WriteLog("PLAYER==========");
		d5 = p->x_pos;
		d6 = p->y_pos;
		VarLog(REG_D5);
		VarLog(REG_D6);*/
	}

	p->art_tile &= 0x7FFF;
	if(o->subtype & 0x40)
		p->art_tile |= 0x8000;
}



// * 10 *
// If you don't know what rings do, you don't know Sonic.
FUNCINLINE void fncRing(ZONE *z, unsigned short NodeNumber)
{
	OBJECT			*o = &objObject[NodeNumber];
	static char		RingSfxPan;

	if(o->static_node == 0
	 && o->x_pos - p->x_pos <= 14
	 && o->x_pos - p->x_pos >= -14
	 && o->y_pos - (p->y_pos & (z->Act[act].Stage[stage].WrapPoint-1)) <= 22
	 && o->y_pos - (p->y_pos & (z->Act[act].Stage[stage].WrapPoint-1)) >= -22)
	{
		o->anim = 1;
		o->anim_frame_duration = GetAnimationSpeed(0x25, (unsigned char *)&o->anim);
		o->static_node = 1;	// Keep in memory until we manually delete it
		++p->Ring_count;
		if(p->Ring_count > 999)
			p->Ring_count = 999;
		else if(p->Ring_count == 100 && (p->Extra_life_flags & 1) == 0){
			p->Extra_life_flags |= 1;
			p->Life_count++;
		}
		else if(p->Ring_count == 200 && (p->Extra_life_flags & 2) == 0){
			p->Extra_life_flags |= 2;
			p->Life_count++;
		}

		RingSfxPan ^= 1;
		if(RingSfxPan)
			PlayPCM(0x35, 1, 1);	// LEFT STEREO
		else
			PlayPCM(0x35, 1, 2);	// RIGHT STEREO
	}

	if(o->static_node)
	{
		o->anim = 1;
		d0 = GetAnimationSpeed(0x25, (unsigned char *)&o->anim);
		ReadAnimation(0x25, (unsigned char *)&o->anim, (unsigned short *)&o->anim_frame, &o->anim_frame_duration, (unsigned char*)&d0);
		DrawAnimation(z, LayerH[frame-1], 0x25, o->anim, o->anim_frame, NORMAL, 0, &o->anim_frame_duration, d0, o->x_pos - p->Camera_X_pos - 8 + 16, o->y_pos - (signed short)(p->Camera_Y_pos) - 8);
		ObjectStates[ObjectNodes[NodeNumber]]++;
	}
	else{
		o->anim = 0;
		ReadAnimation(0x25, (unsigned char *)&o->anim, (unsigned short *)&o->anim_frame, &o->anim_frame_duration, (unsigned char*)&d0);
		d0 = GetAnimationSpeed(0x25, (unsigned char *)&o->anim);
		o->anim_frame = (ticCounterL % (((d0+1) << 2)) >> 3);
		DrawAnimation(z, LayerH[frame-1], 0x25, o->anim, o->anim_frame, NORMAL, 0, &o->anim_frame_duration, d0, o->x_pos - p->Camera_X_pos - 8 + 16, o->y_pos - (signed short)(p->Camera_Y_pos) - 8);
	}

	if(o->static_node && o->anim_frame_duration < 0 && o->anim_frame == 3)
		DestroyObject(NodeNumber);
}



void RunFunction(unsigned char function){
	int i;

	if(obj_script) free(obj_script);
	obj_script = (char *)malloc(game_script_size[function]);
	for(i=0; i < game_script_size[function]; i++)
		obj_script[i] = script[game_script_start[function] + i];

	//if(obj_script_type[function] == SCRIPT_TYPE_PROCODE){	// Not a 68000 binary file
		fncProcode(0);
		return;
	//}
}



void fncProcode(unsigned short NodeNumber){
	int i;

	int src;
	int dest;
	int op;
	int type1;
	int type2;
	int type3;
	int type4;
	int type5;
	int type6;
	int type7;
	int type8;
	int type9;
	int type10;
	int size1;
	int size2;
	int size3;
	int size4;
	int size5;
	int size6;
	int size7;
	int size8;
	int size9;
	int size10;
	int num1;
	int num2;
	int num3;
	int num4;
	int num5;
	int num6;
	int num7;
	int num8;
	int num9;
	int num10;
	int ptr;
	char string[64];

	OBJECT *o = &objObject[NodeNumber];

	internal_ovar_ptrs[0] = (int *)&o->user[0];
	internal_ovar_ptrs[1] = (int *)&o->static_node;
	internal_ovar_ptrs[2] = (int *)&o->h_tag;
	internal_ovar_ptrs[3] = (int *)&o->l_tag;
	internal_ovar_ptrs[4] = (int *)&o->type;
	internal_ovar_ptrs[5] = (int *)&o->routine;
	internal_ovar_ptrs[6] = (int *)&o->status;
	internal_ovar_ptrs[7] = (int *)&o->x_pos;
	internal_ovar_ptrs[8] = (int *)&o->y_pos;
	internal_ovar_ptrs[9] = (int *)&o->render_flags;
	internal_ovar_ptrs[10] = (int *)&o->width_pixels;
	internal_ovar_ptrs[11] = (int *)&o->priority;
	internal_ovar_ptrs[12] = (int *)&o->subtype;
	internal_ovar_ptrs[13] = (int *)&o->objoff_32;
	internal_ovar_ptrs[14] = (int *)&o->objoff_34;
	internal_ovar_ptrs[15] = (int *)&o->anim_frame_duration;
	internal_ovar_ptrs[16] = (int *)&o->anim_frame;
	internal_ovar_ptrs[17] = (int *)&o->anim;
	internal_ovar_ptrs[18] = (int *)&o->x_pos_pre;
	internal_ovar_ptrs[19] = (int *)&o->y_pos_pre;
	internal_ovar_ptrs[20] = (int *)&o->x_vel;
	internal_ovar_ptrs[21] = (int *)&o->y_vel;
	internal_ovar_ptrs[22] = (int *)&o->x_radius;
	internal_ovar_ptrs[23] = (int *)&o->y_radius;

	script_pos = 0;
	if_scope = 0;
	break_ptr[0] = -1;

	while(script_pos >= 0){
		switch(obj_script[script_pos]){
			case 0x0:		// assignment
				script_pos++;

				type1 = obj_script[script_pos];
				script_pos++;

				// Get destination
				i = *(short *)(&obj_script[script_pos]);
				script_pos += 2;
				if(i >= 0x800){	// GVAR
					i -= 0x800;
					dest = (int)internal_gvar_ptrs[i];
					size1 = internal_gvar_size[i];
				}
				else if(i >= 0x100){	// OVAR
					i -= 0x100;
					dest = (int)internal_ovar_ptrs[i];
					size1 = internal_ovar_size[i];
				}
				else{			// PVAR
					dest = (int)internal_pvar_ptrs[frame-1][i];
					size1 = internal_pvar_size[i];
				}

				if(type1 == 2){
					type3 = obj_script[script_pos];
					script_pos++;

					// Get destination subscript
					if(type3 == 0){		// immediate
						dest += ((*(int *)(&obj_script[script_pos])) * size1);
						script_pos += 4;
					}
					else{				// variable
						i = *(short *)(&obj_script[script_pos]);
						script_pos += 2;
						if(i >= 0x800){	// GVAR
							i -= 0x800;
							switch(internal_gvar_size[i]){
								case 4:
									dest += ((*(int *)internal_gvar_ptrs[i]) * size1);
									break;
								case 2:
									dest += ((*(short *)internal_gvar_ptrs[i]) * size1);
									break;
								case 1:
									dest += ((*(char *)internal_gvar_ptrs[i]) * size1);
							}
						}
						else if(i >= 0x100){	// OVAR
							i -= 0x100;
							switch(internal_ovar_size[i]){
								case 4:
									dest += ((*(int *)internal_ovar_ptrs[i]) * size1);
									break;
								case 2:
									dest += ((*(short *)internal_ovar_ptrs[i]) * size1);
									break;
								case 1:
									dest += ((*(char *)internal_ovar_ptrs[i]) * size1);
							}
						}
						else{			// PVAR
							switch(internal_pvar_size[i]){
								case 4:
									dest += ((*(int *)internal_pvar_ptrs[frame-1][i]) * size1);
									break;
								case 2:
									dest += ((*(short *)internal_pvar_ptrs[frame-1][i]) * size1);
									break;
								case 1:
									dest += ((*(char *)internal_pvar_ptrs[frame-1][i]) * size1);
							}
						}
					}
				}

				// Get operation
				op = obj_script[script_pos];
				script_pos++;

				// Get source
				if(op > 2){
					type2 = obj_script[script_pos];
					script_pos++;

					if(type2 == 0){		// immediate
						src = *(int *)(&obj_script[script_pos]);
						size2 = 0;
						script_pos += 4;
					}
					else{				// variable
						i = *(short *)(&obj_script[script_pos]);
						script_pos += 2;
						if(i >= 0x800){	// GVAR
							i -= 0x800;
							src = (int)internal_gvar_ptrs[i];
							size2 = internal_gvar_size[i];
						}
						else if(i >= 0x100){	// OVAR
							i -= 0x100;
							src = (int)internal_ovar_ptrs[i];
							size2 = internal_ovar_size[i];
						}
						else{			// PVAR
							src = (int)internal_pvar_ptrs[frame-1][i];
							size2 = internal_pvar_size[i];
						}
					}

					if(type2 == 2){
						type4 = obj_script[script_pos];
						script_pos++;

						// Get source subscript
						if(type4 == 0){		// immediate
							src += ((*(int *)(&obj_script[script_pos])) * size2);
							script_pos += 4;
						}
						else{				// variable
							i = *(short *)(&obj_script[script_pos]);
							script_pos += 2;
							if(i >= 0x800){	// GVAR
								i -= 0x800;
								switch(internal_gvar_size[i]){
									case 4:
										src += ((*(int *)internal_gvar_ptrs[i]) * size2);
										break;
									case 2:
										src += ((*(short *)internal_gvar_ptrs[i]) * size2);
										break;
									case 1:
										src += ((*(char *)internal_gvar_ptrs[i]) * size2);
								}
							}
							else if(i >= 0x100){	// OVAR
								i -= 0x100;
								switch(internal_ovar_size[i]){
									case 4:
										src += ((*(int *)internal_ovar_ptrs[i]) * size2);
										break;
									case 2:
										src += ((*(short *)internal_ovar_ptrs[i]) * size2);
										break;
									case 1:
										src += ((*(char *)internal_ovar_ptrs[i]) * size2);
								}
							}
							else{			// PVAR
								switch(internal_pvar_size[i]){
									case 4:
										src += ((*(int *)internal_pvar_ptrs[frame-1][i]) * size2);
										break;
									case 2:
										src += ((*(short *)internal_pvar_ptrs[frame-1][i]) * size2);
										break;
									case 1:
										src += ((*(char *)internal_pvar_ptrs[frame-1][i]) * size2);
								}
							}
						}
					}
				}
				procode_set(size1, dest, op, size2, src);
				break;
			case 0x6:		// "if"
				script_pos++;

				// Get next branch ptr
				ptr = *(int *)(&obj_script[script_pos]);
				script_pos += 4;

				// Get endif ptr
				break_ptr[if_scope+1] = *(int *)(&obj_script[script_pos]);
				script_pos += 4;

				// Get destination
				type1 = obj_script[script_pos];
				script_pos++;

				if(type1 == 0){		// immediate
					dest = *(int *)(&obj_script[script_pos]);
					size1 = 0;
					script_pos += 4;
				}
				else{				// variable
					i = *(short *)(&obj_script[script_pos]);
					script_pos += 2;
					if(i >= 0x800){	// GVAR
						i -= 0x800;
						dest = (int)internal_gvar_ptrs[i];
						size1 = internal_gvar_size[i];
					}
					else if(i >= 0x100){	// OVAR
						i -= 0x100;
						dest = (int)internal_ovar_ptrs[i];
						size1 = internal_ovar_size[i];
					}
					else{			// PVAR
						dest = (int)internal_pvar_ptrs[frame-1][i];
						size1 = internal_pvar_size[i];
					}
				}

				// Get operation
				op = obj_script[script_pos];
				script_pos++;

				// Get source
				type2 = obj_script[script_pos];
				script_pos++;

				if(type2 == 0){		// immediate
					src = *(int *)(&obj_script[script_pos]);
					size2 = 0;
					script_pos += 4;
				}
				else{				// variable
					i = *(short *)(&obj_script[script_pos]);
					script_pos += 2;
					if(i >= 0x800){	// GVAR
						i -= 0x800;
						src = (int)internal_gvar_ptrs[i];
						size2 = internal_gvar_size[i];
					}
					else if(i >= 0x100){	// OVAR
						i -= 0x100;
						src = (int)internal_ovar_ptrs[i];
						size2 = internal_ovar_size[i];
					}
					else{			// PVAR
						src = (int)internal_pvar_ptrs[frame-1][i];
						size2 = internal_pvar_size[i];
					}
				}
				i = procode_if(size1, dest, op, size2, src);

				if(i)
					if_scope++;
				else{
				//	if(ptr)
						script_pos = ptr;
				//	else	// fix for when pointer is zero
				//		script_pos = break_ptr[if_scope+1];
				}
				break;
			case 0x7:		// "elseif"
				script_pos++;

				// Get next branch ptr
				ptr = *(int *)(&obj_script[script_pos]);
				script_pos += 4;

				// Get destination
				type1 = obj_script[script_pos];
				script_pos++;

				if(type1 == 0){		// immediate
					dest = *(int *)(&obj_script[script_pos]);
					size1 = 0;
					script_pos += 4;
				}
				else{				// variable
					i = *(short *)(&obj_script[script_pos]);
					script_pos += 2;
					if(i >= 0x800){	// GVAR
						i -= 0x800;
						dest = (int)internal_gvar_ptrs[i];
						size1 = internal_gvar_size[i];
					}
					else if(i >= 0x100){	// OVAR
						i -= 0x100;
						dest = (int)internal_ovar_ptrs[i];
						size1 = internal_ovar_size[i];
					}
					else{			// PVAR
						dest = (int)internal_pvar_ptrs[frame-1][i];
						size1 = internal_pvar_size[i];
					}
				}

				// Get operation
				op = obj_script[script_pos];
				script_pos++;

				// Get source
				type2 = obj_script[script_pos];
				script_pos++;

				if(type2 == 0){		// immediate
					src = *(int *)(&obj_script[script_pos]);
					size2 = 0;
					script_pos += 4;
				}
				else{				// variable
					i = *(short *)(&obj_script[script_pos]);
					script_pos += 2;
					if(i >= 0x800){	// GVAR
						i -= 0x800;
						src = (int)internal_gvar_ptrs[i];
						size2 = internal_gvar_size[i];
					}
					else if(i >= 0x100){	// OVAR
						i -= 0x100;
						src = (int)internal_ovar_ptrs[i];
						size2 = internal_ovar_size[i];
					}
					else{			// PVAR
						src = (int)internal_pvar_ptrs[frame-1][i];
						size2 = internal_pvar_size[i];
					}
				}
				i = procode_if(size1, dest, op, size2, src);

				if(i)
					if_scope++;
				else{
				//	if(ptr)
						script_pos = ptr;
				//	else	// fix for when pointer is zero
				//		script_pos = break_ptr[if_scope+1];
				}
				break;
			case 0xA:		// "break"
				script_pos = break_ptr[if_scope];
				if_scope--;
				break;
			case 0xD:		// "playfm"
				script_pos++;

				// FM number
				procode_process_number(&type1, &src, &size1, 2);
				// buffer
				procode_process_number(&type2, &dest, &size2, 1);
				// mix
				procode_process_number(&type3, &op, &size3, 1);

				procode_playfm(size1, src, size2, dest, size3, op);
				break;
			case 0xE:		// "playpcm"
				script_pos++;

				// PCM number
				procode_process_number(&type1, &src, &size1, 2);
				// buffer
				procode_process_number(&type2, &dest, &size2, 1);
				// mix
				procode_process_number(&type3, &op, &size3, 1);

				procode_playpcm(size1, src, size2, dest, size3, op);
				break;
			case 0xF:		// "resetsound"
				script_pos++;

				ResetSound();
				break;
			case 0x10:		// "textout"
				script_pos++;

				// X position
				procode_process_number(&type1, &num1, &size1, 2);
				// Y position
				procode_process_number(&type2, &num2, &size2, 2);
				// Color
				procode_process_number(&type3, &num3, &size3, 1);

				for(i=0; i < 64; i++){
					string[i] = obj_script[script_pos];
					script_pos++;
					if(string[i] == 0)
						i = 64;
				}

				procode_textout(size1, num1, size2, num2, size3, num3, string);
				break;
			case 0x11:		// "drawsprite"
				script_pos++;

				// Layer
				procode_process_number(&type1, &num1, &size1, 1);
				/*
					// Sheet
					procode_process_number(&type2, &num2, &size2, 1);
					// Sprite
					procode_process_number(&type3, &num3, &size3, 1);
				*/
				// Drawing flags
				procode_process_number(&type4, &num4, &size4, 1);
				// Translucency
				procode_process_number(&type5, &num5, &size5, 1);
				// X position
				procode_process_number(&type6, &num6, &size6, 2);
				// Y position
				procode_process_number(&type7, &num7, &size7, 2);

				procode_drawsprite(NodeNumber, size1, num1, size4, num4, size5, num5, size6, num6, size7, num7);
				break;
			case 0x12:		// "animate"
				script_pos++;

				// Layer
				procode_process_number(&type1, &num1, &size1, 1);
				/*
					// Sheet
					procode_process_number(&type2, &num2, &size2, 1);
					// Animation
					procode_process_number(&type3, &num3, &size3, 1);
					// Frame
					procode_process_number(&type4, &num4, &size4, 2);
				*/
				// Drawing flags
				procode_process_number(&type5, &num5, &size5, 1);
				// Translucency
				procode_process_number(&type6, &num6, &size6, 1);
				/*
					// Frame duration
					procode_process_number(&type7, &num7, &size7, 1);
					// Speed
					procode_process_number(&type8, &num8, &size8, 1);
				*/
				// X position
				procode_process_number(&type9, &num9, &size9, 2);
				// Y position
				procode_process_number(&type10, &num10, &size10, 2);

				procode_animate(NodeNumber, size1, num1, size5, num5, size6, num6, size9, num9, size10, num10);
				break;
			case 0x13:		// "destroy"
				DestroyObject(NodeNumber);
			case 0x14:		// "return"
				return;
			case 0x15:		// "counterout"
				script_pos++;

				// Type
				procode_process_number(&type1, &num1, &size1, 1);
				// Fill
				procode_process_number(&type2, &num2, &size2, 1);
				// Number
				procode_process_number(&type3, &num3, &size3, 4);
				// X
				procode_process_number(&type4, &num4, &size4, 2);
				// Y
				procode_process_number(&type5, &num5, &size5, 2);

				procode_counterout(size1, num1, size2, num2, size3, num3, size4, num4, size5, num5);
				break;
			case 0x16:		// "fadeoutfm"
				script_pos++;

				// buffer
				procode_process_number(&type1, &num1, &size1, 1);

				procode_fadeoutfm(size1, num1);
				break;
			case 0x17:		// "move"
				script_pos++;

				procode_move(NodeNumber);
				break;
			case 0x18:		// "spawn"
				script_pos++;

				// type
				procode_process_number(&type1, &num1, &size1, 1);
				// subtype
				procode_process_number(&type2, &num2, &size2, 1);
				// high tag
				procode_process_number(&type3, &num3, &size3, 1);
				// low tag
				procode_process_number(&type4, &num4, &size4, 1);
				// x position
				procode_process_number(&type5, &num5, &size5, 2);
				// y position
				procode_process_number(&type6, &num6, &size6, 2);

				procode_spawn(size1, num1, size2, num2, size3, num3, size4, num4, size5, num5, size6, num6);
				break;
			case 0x19:		// "rest"
				script_pos++;

				// milliseconds
				procode_process_number(&type1, &num1, &size1, 2);

				procode_rest(size1, num1);
				break;
			case 0x1A:		// "setgfxmode"
				script_pos++;

				// res_x
				procode_process_number(&type1, &num1, &size1, 2);
				// res_y
				procode_process_number(&type2, &num2, &size2, 2);
				// pad_x
				procode_process_number(&type3, &num3, &size3, 2);
				// pad_y
				procode_process_number(&type4, &num4, &size4, 2);
				// dbl_x
				procode_process_number(&type5, &num5, &size5, 2);
				// dbl_y
				procode_process_number(&type6, &num6, &size6, 2);
				// full
				procode_process_number(&type7, &num7, &size7, 1);

				procode_setgfxmode(size1, num1, size2, num2, size3, num3, size4, num4, size5, num5, size6, num6, size7, num7);
				break;
			case 0x1B:		// "startzone"
				script_pos++;

				// zone
				procode_process_number(&type1, &num1, &size1, 1);
				// act
				procode_process_number(&type2, &num2, &size2, 1);
				// stage
				procode_process_number(&type3, &num3, &size3, 1);

				procode_startzone(size1, num1, size2, num2, size3, num3);
				break;
			default:		// !!! ERROR !!!
				allegro_message("Error found in script:\n\no->type = 0x%X\nscript_pos = 0x%X\nobj_script[script_pos] = 0x%X",
				 objObject[NodeNumber].type, script_pos, obj_script[script_pos]);
				return;
		}
	}

	return;
}



void fncM68K(ZONE *z, unsigned short NodeNumber){
	OBJECT *o = &objObject[NodeNumber];

	/*if(o->type == 0xD){
		DrawCounter16(LayerH[frame-1], obj_script_size[o->type], 0, 0);
		DrawCounter16(LayerH[frame-1], obj_script_type[o->type], 35, 0);
		DrawCounter16(LayerH[frame-1], Update_HUD_timer, 70, 0);
		DrawCounter16(LayerH[frame-1], Two_player_mode, 105, 0);
	}*/

	if(obj_script_size[o->type] == 0)
		return;

	if(obj_script) free(obj_script);
	obj_script = (char *)malloc(obj_script_size[o->type]);
	for(i=0; i < obj_script_size[o->type]; i++)
		obj_script[i] = script[obj_script_start[o->type] + i];


	if(obj_script_type[o->type] == SCRIPT_TYPE_PROCODE){	// Not a 68000 binary file
		fncProcode(NodeNumber);
		return;
	}


	//if(p->x_pos < 0x1000){ p->x_pos = 0x1000; p->y_pos = 0x200; p->Camera_X_pos = 0x1000; p->Camera_Y_pos = 0x200; }

	//o->subtype = 0x82;
	o->subtype = o->subtype;
	if(o->status == 0) o->status = (o->y_pos >> 13);

	o->ram[0x0] = o->type;
	o->ram[0x8] = o->x_pos >> 8;
	o->ram[0x9] = o->x_pos;
	o->ram[0xC] = (o->y_pos >> 8) & 0x1F;
	o->ram[0xD] = o->y_pos;
	o->ram[0x22] = o->status;
	o->ram[0x28] = o->subtype;

	//DrawCounter16(LayerH[frame-1], o->subtype + (o->type << 8), o->x_pos - p->Camera_X_pos - 16 + 16, (o->y_pos & 0x1FFF) - p->Camera_Y_pos - 16);

	for(i=0; i < 0x1300; i++)
		ram_68k[0xFFFF - 0xB100 - i] = o->ram[i];

	reg_a[0] = 0xFFFFB100;	// last object in object RAM (this object)
	reg_a[7] = 0xFFFFFFFC;

	RunScript(NodeNumber);

	/*reg_a[0] = 0xFFFFB140;	// last object in object RAM (this object)
	reg_a[7] = 0xFFFFFFFC;
	RunScript(NodeNumber);

	reg_a[0] = 0xFFFFB180;	// last object in object RAM (this object)
	reg_a[7] = 0xFFFFFFFC;
	RunScript(NodeNumber);*/

	//o->x_pos = (ram_68k[0xFFFF - 0xB108] << 8) + ram_68k[0xFFFF - 0xB109];
	//o->y_pos = (ram_68k[0xFFFF - 0xB10C] << 8) + ram_68k[0xFFFF - 0xB10D];
	//o->subtype = ram_68k[0xFFFF - 0xB128];

	//DrawCounter16(LayerSH[frame-1], ram_68k[0xFFFF - 0xF7B2], 120, 0);

	/*if(p->x_pos > 0x2200 && p->y_pos > 0x380 && ram_68k[0xFFFF - 0xB124] == 2 && (p->anim == 2 || p->anim == 3)){
		DumpLog("Motorola.log");
		allegro_message("!");
		rest(40);
	}*/

	for(i=0; i < 0x1300; i++)
		o->ram[i] = ram_68k[0xFFFF - 0xB100 - i];

	o->status = o->ram[0x22];
}







// These are needed to port "prosonic_lift.asm"
/*
void MvSonicOnPtfm(){
	d0 = o->y_pos;
	d0 -= d3;
	// Skip these lines of code since they're unused anyway
	// bra.s loc_19BA2
	// move.w y_pos(a0),d0
	// subi.w #9,d0

loc_19BA2:
	if(p->obj_control < 0)
		goto return_19BCA;
	if((unsigned char)p->routine >= 6)
		goto return_19BCA;
	if(Debug_placement_mode)
		goto return_19BCA;

	d1 = 0;
	d1 = p->y_radius;
	d0 -= d1;
	p->y_pos = d0;
	d2 -= o->x_pos;
	p->x_pos -= d2;

return_19BCA:
	return;
}

void PlatformObject(){
	// lea (MainCharacter).w,a1
	d6 = 3;
	stack[1] = d1;
	stack[2] = d2;
	stack[3] = d3;
	stack[4] = d4;
	PlatformObject_SingleCharacter();
	d1 = stack[1];
	d2 = stack[2];
	d3 = stack[3];
	d4 = stack[4];
	// lea (Sidekick).w,a1
	d6++;

	PlatformObject_SingleCharacter();
	return;
}

void PlatformObject_SingleCharacter(){
	if(o->status & (1 << d6) == 0){
		//goto loc_19DBA;
		loc_19DBA();
		return;
	}
	d2 = d1;
	d2 += d2;
	if(p->status & 2 == 0){
		d0 = p->x_pos;
		d0 -= o->x_pos;
		d0 += d1;
		if((short)d0 >= 0){
			if((unsigned short)d0 < d2)
				goto loc_19C80;
		}
	}

	p->status &= 0xF7;
	p->status |= 2;
	o->status &= ((1 << d6) ^ 0xFF);
	d4 = 0;
	return;

loc_19C80:
	d2 = d4;
	MvSonicOnPtfm();
	d4 = 0;
	return;
}

void loc_19DBA(){
	if(p->y_vel < 0)
		goto return_19E8E;
	d0 = p->x_pos;
	d0 -= o->x_pos;
	d0 += d1;
	if(d0 < 0)
		goto return_19E8E;
	if((unsigned short)d0 >= d1)
		goto return_19E8E;

loc_19DD8:
	d0 = o->y_pos;
	d0 -= d3;

loc_19DDE:
	d2 = p->y_pos;
	d1 = p->y_radius;
	d1 += d2;
	d1 += 4;
	d0 -= d1;

	if((short)d0 > 0)
		goto return_19E8E;
	if((short)d0 < -10)
		goto return_19E8E;
	if(p->obj_control < 0)
		goto return_19E8E;
	if(p->routine >= 6)
		goto return_19E8E;

	d2 += d0;
	d2 += 3;
	p->y_pos = d2;

loc_19E14:
	if((p->status & 8) == 0)
		goto loc_19E30;
	// moveq	#0,d0
	// move.b	interact(a1),d0
	// lsl.w	#6,d0
	// addi.l	#Object_RAM,d0
	// movea.l	d0,a3	; a3=object
	// bclr		d6,status(a3)

loc_19E30:
	// FINISH ME! FINISH ME! FINISH ME!
}*/
